package IC.AST.SemanticAnalysis;

import IC.AST.*;
import IC.Error.ErrorStack;
import IC.Error.Error.ErrorType;
import IC.Error.ErrorStringIntervaled;
import IC.SymbolTables.Types.MethodType;
import IC.SymbolTables.Types.VoidType;

/**
 * 
 * Checks that there is a return type on any flow path
 * If all control flows in a node return then node.visit(this) == true else null
 * 
 * BONUS!!!!(*)%*#@)%(*#%)(#@*!!!
 */
class CheckReturnVisitor extends UnreachableCodeVisitor 
{
	public Object Visit(ClassDeclaration node)
	{
		_classID = node.GetID();
		return VisitSons(node);
	}
	
	public Object Visit(Method node)
	{
		_funcName = node.GetID();
		if (!((MethodType)node.GetType())
				.GetReturnType().IsInstanceOf(new VoidType()) 
			&&
				node.GetScope().Visit(this) == null)
			ErrorStack.Push(
					new ErrorStringIntervaled(
							ErrorType.Semantic, 
							String.format("A method '%s' of a none void type in class '%s' must have a return statement on any posible control flow", 
									_funcName, _classID), 
						node.GetInterval()));
		return null;
	}

	public Object Visit(ReturnStatement node) { return true; }
	
	public Object Visit(ScopeStatement node) { return CheckForUnreachableCode(node, "return"); }
	
	
	//Let Haim take a look!
	public Object Visit(WhileStatement node) 
	{
		return ((node.GetExpression() instanceof LiteralExpression) 
				&& 
					((LiteralExpression)node.GetExpression()).GetLiteral() instanceof BooleanLiteral
				&&
					(((BooleanLiteral)((LiteralExpression)node.GetExpression()).GetLiteral()).GetVaule() == true))
			?
				node.GetSatement().Visit(this)
			:
				VisitSons(node);
	}
}
